/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.lang.util;

import cn.easyplatform.castor.Castors;
import cn.easyplatform.lang.Mirror;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public abstract class AbstractContext implements Context {

	public AbstractContext() {
		super();
	}

	public boolean isEmpty() {
		return size() == 0;
	}

	public Object get(String name, Object dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return obj;
	}

	public <T> T getAs(Class<T> type, String name) {
		return Castors.me().castTo(get(name), type);
	}

	public <T> T getAs(Class<T> type, String name, T dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return Castors.me().castTo(obj, type);
	}

	public int getInt(String name) {
		return getInt(name, -1);
	}

	public String getString(String name) {
		return getString(name, null);
	}

	public boolean getBoolean(String name) {
		return getBoolean(name, false);
	}

	public float getFloat(String name) {
		return getFloat(name, 0.0f);
	}

	public double getDouble(String name) {
		return getDouble(name, 0.0);
	}

	public double getDouble(String name, double dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return Double.parseDouble(obj.toString());
	}

	public int getInt(String name, int dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return Integer.parseInt(obj.toString());
	}

	public String getString(String name, String dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return obj.toString();
	}

	public boolean getBoolean(String name, boolean dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return Boolean.parseBoolean(obj.toString());
	}

	public float getFloat(String name, float dft) {
		Object obj = get(name);
		if (null == obj)
			return dft;
		return Float.parseFloat(obj.toString());
	}

	public Context putAll(Object obj) {
		return putAll(null, obj);
	}

	public Context putAll(String prefix, Object obj) {
		if (null != obj) {
			// Context
			if (obj instanceof Context) {
				for (String key : ((Context) obj).keys()) {
					if (null != prefix)
						key = prefix + key;
					this.set(key, ((Context) obj).get(key));
				}
			}
			// Map
			else if (obj instanceof Map<?, ?>) {
				for (Map.Entry<?, ?> en : ((Map<?, ?>) obj).entrySet()) {
					Object oKey = en.getKey();
					if (null == oKey)
						continue;
					String key = oKey.toString();
					if (null != prefix)
						key = prefix + key;
					this.set(key.toString(), en.getValue());
				}
			}
			// 普通 Java 对象
			else {
				Mirror<?> mirror = Mirror.me(obj);
				// 需要被忽略的 Java 对象
				if (mirror.getType().isArray() || mirror.isNumber()
						|| mirror.isBoolean() || mirror.isChar()
						|| mirror.isStringLike() || mirror.isDateTimeLike()
						|| Collection.class.isAssignableFrom(mirror.getType())) {
				}
				// 普通 Java 对象，应该取其每个字段
				else {
					for (Field field : mirror.getFields()) {
						String key = field.getName();
						if (null != prefix)
							key = prefix + key;
						this.set(key, mirror.getValue(obj, field));
					}
				}
			}
		}
		return this;
	}

	@SuppressWarnings("unchecked")
	public Map<String, Object> getMap(String name) {
		return getAs(Map.class, name);
	}

	@SuppressWarnings("unchecked")
	public List<Object> getList(String name) {
		return getAs(List.class, name);
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> getList(Class<T> classOfT, String name) {
		return (List<T>) getList(name);
	}

	public AbstractContext clone() {
		return null;
	};

}